package edu.gmu.dglidde2.ece612.scheduler;

import org.junit.Before;
import org.junit.Test;

/**
 * Unit test suite for the unsuccessful scheduling of tasks.
 * 
 * @author Doug Glidden
 */
public class ReportSchedulingErrors {

	private SchedulerImpl scheduler;

	/**
	 * Creates a {@link SchedulerImpl} to be used in the test.
	 * 
	 * @see Before
	 */
	@Before
	public void createScheduler() {
		scheduler = new SchedulerImpl();
	}

	/**
	 * Tests the unsuccessful adding of a {@code null} processor.
	 */
	@Test(expected = IllegalArgumentException.class)
	public void testNullProcessor() {
		scheduler.addProcessor(null);
	}

	/**
	 * Tests the unsuccessful adding of an empty string as a processor.
	 */
	@Test(expected = IllegalArgumentException.class)
	public void testEmptyProcessor() {
		scheduler.addProcessor("");
	}

	/**
	 * Tests the unsuccessful adding of a {@code null} task.
	 */
	@Test(expected = IllegalArgumentException.class)
	public void testNullTask() {
		scheduler.addTask(null);
	}

	/**
	 * Tests the unsuccessful adding of an invalid task.
	 */
	@Test(expected = IllegalArgumentException.class)
	public void testInvalidTask() {
		scheduler.addTask(new Task());
	}

	/**
	 * Tests unsuccessful scheduling with no processors specified.
	 */
	@Test(expected = MissingDataException.class)
	public void testWithoutProcessors() throws MissingDataException,
			NoFeasibleScheduleException {
		Task task = new Task();
		task.setName("test-task");
		task.setPhase(0);
		task.setPeriod(10);
		task.setExecutionTime(1);
		task.setRelativeDeadline(10);
		scheduler.addTask(task);

		scheduler.generateSchedule();
	}

	/**
	 * Tests unsuccessful scheduling with no tasks specified.
	 */
	@Test(expected = MissingDataException.class)
	public void testWithoutTasks() throws MissingDataException,
			NoFeasibleScheduleException {
		scheduler.addProcessor("P0");
		scheduler.generateSchedule();
	}

	/**
	 * Tests unsuccessful scheduling when the deadline of a task with no slack
	 * is overrun.
	 */
	@Test(expected = NoFeasibleScheduleException.class)
	public void testDeadlineOverrunNoSlack() throws MissingDataException,
			NoFeasibleScheduleException {
		scheduler.addProcessor("P0");

		Task[] tasks = new Task[3];
		tasks[0] = new Task();
		tasks[0].setName("task0");
		tasks[0].setPhase(2);
		tasks[0].setPeriod(5);
		tasks[0].setExecutionTime(2);
		tasks[0].setRelativeDeadline(4);

		tasks[1] = new Task();
		tasks[1].setName("task1");
		tasks[1].setPhase(3);
		tasks[1].setPeriod(10);
		tasks[1].setExecutionTime(3);
		tasks[1].setRelativeDeadline(3);

		tasks[2] = new Task();
		tasks[2].setName("task2");
		tasks[2].setPhase(5);
		tasks[2].setPeriod(10);
		tasks[2].setExecutionTime(2);
		tasks[2].setRelativeDeadline(5);

		for (Task task : tasks) {
			scheduler.addTask(task);
		}

		scheduler.generateSchedule();
	}

	/**
	 * Tests unsuccessful scheduling when the deadline of a task with slack is
	 * overrun.
	 */
	@Test(expected = NoFeasibleScheduleException.class)
	public void testDeadlineOverrunInsufficientSlack()
			throws MissingDataException, NoFeasibleScheduleException {
		scheduler.addProcessor("P0");

		Task[] tasks = new Task[2];
		tasks[0] = new Task();
		tasks[0].setName("task0");
		tasks[0].setPhase(0);
		tasks[0].setPeriod(10);
		tasks[0].setExecutionTime(8);
		tasks[0].setRelativeDeadline(10);

		tasks[1] = new Task();
		tasks[1].setName("task1");
		tasks[1].setPhase(0);
		tasks[1].setPeriod(10);
		tasks[1].setExecutionTime(8);
		tasks[1].setRelativeDeadline(10);

		for (Task task : tasks) {
			scheduler.addTask(task);
		}

		scheduler.generateSchedule();
	}

	/**
	 * Tests unsuccessful scheduling when the length of a period is overrun.
	 */
	@Test(expected = NoFeasibleScheduleException.class)
	public void testPeriodOverrun() throws MissingDataException,
			NoFeasibleScheduleException {
		scheduler.addProcessor("P0");

		Task[] tasks = new Task[3];
		tasks[0] = new Task();
		tasks[0].setName("task0");
		tasks[0].setPhase(0);
		tasks[0].setPeriod(5);
		tasks[0].setExecutionTime(3);
		tasks[0].setRelativeDeadline(6);

		tasks[1] = new Task();
		tasks[1].setName("task1");
		tasks[1].setPhase(3);
		tasks[1].setPeriod(10);
		tasks[1].setExecutionTime(3);
		tasks[1].setRelativeDeadline(4);

		tasks[2] = new Task();
		tasks[2].setName("task2");
		tasks[2].setPhase(5);
		tasks[2].setPeriod(10);
		tasks[2].setExecutionTime(2);
		tasks[2].setRelativeDeadline(10);

		for (Task task : tasks) {
			scheduler.addTask(task);
		}

		scheduler.generateSchedule();
	}

}
